#include <process.h>
#include <windows.h>

#pragma comment(lib, "util.lib")

#include <ballade/smartclient/reader_thread.h>
#include <ballade/smartclient/header.h>
#include <ballade/smartclient/header_creater.h>
#include <ballade/smartclient/dispatcher.h>

namespace Ballade
{
	namespace SmartClient
	{
		// Constructor and Deconstructor
		ReaderThread::ReaderThread(Network::Socket& socket, Dispatcher &dispatcher) :
			_socket(socket),
			_dispatcher(dispatcher)
		{
			_terminated = true;
			_headerCreater = NULL;
		}

		ReaderThread::~ReaderThread()
		{
			Logger_.close();
		}
		// End of Constructor and Deconstructor

		// Public
		void ReaderThread::start()
		{			
			_terminated = false;
			unsigned threadId;
			_beginthreadex(NULL, 0, &ReaderThread::run, (void *)this, 0, &threadId);
		}

		void ReaderThread::stop()
		{
			_terminated = true;
			Sleep(2000);
		}

		const bool ReaderThread::isTerminated() const
		{
			return _terminated;
		}

		void ReaderThread::setHeaderCreater(HeaderCreater *creater)
		{
			_headerCreater = creater;
		}

		// End of Public

		// Protected
		// End of Protected

		// Private
		unsigned ReaderThread::run(void *args)
		{
			Logger_.info("ReaderThread(run) - Start reading thread");
			ReaderThread *reader = (ReaderThread *)args;
			
			Network::InputStream in = reader->_socket.getInputStream();

			while(!reader->isTerminated())
			{
				try
				{
					char *data = NULL;
					if(reader->_headerCreater)
					{
						Header& header = reader->_headerCreater->createEmptyHeader();
						int headerLen = header.getLength();

						data = new char[headerLen + 1];
						memset(data, 0x00, headerLen + 1);
						
						int rlen = in.read(data, headerLen);
						
						if(rlen == headerLen)
						{
							header.setRawValue(data);

							int dataLen = header.getBodyLength();
							
							if(Logger_.isDebugEnabled())
							{
								Logger_.debug("ReaderThread(run) - Packet ID: %s", header.getName());
								Logger_.debug("ReaderThread(run) - Packet Body Length: %d", dataLen);
							}
							
							if(dataLen > 0)
							{
								if(data) delete data;
								data = new char[dataLen + 1];
								memset(data, 0x00, dataLen + 1);
								rlen += in.read(data, dataLen);
								if(rlen - header.getLength() == dataLen)
								{
									reader->_dispatcher.dispatch(header.getName(), data);
								}
							}
						}
						
						if(data) delete data;
						
						Sleep(1000);
					}
				}
				catch (Network::SocketError &e)
				{
					reader->_terminated = true;
					Logger_.error("ReaderThread(run) - %s", e.what());
					break;
				}
			}
			Logger_.info("ReaderThread(run) - Reading thread exit");
			_endthreadex(0);
			return 0;
		}

		Util::Logger& ReaderThread::Logger_ = Util::Logger::getInstance();
		// End of Private
	}
}